bin/show: Add --print-sizes option to show sizes metadata
authorDan Nicholson <nicholson@endlessm.com>
Thu, 24 Oct 2019 21:21:49 +0000 (15:21 -0600)
committerDan Nicholson <nicholson@endlessm.com>
Tue, 21 Jan 2020 03:46:31 +0000 (20:46 -0700)
Use the new `ostree_commit_get_object_sizes()` API to read the
`ostree.sizes` commit metadata and print a summary.

Makefile-tests.am
bash/ostree
man/ostree-show.xml
src/ostree/ot-builtin-show.c
tests/test-pull-sizes.sh [new file with mode: 0755]

index a4acb8e0d8368dc37b6c8c7ab3eb32c36dfb70a2..615b8480c1a0fba4b50bff30ae90f55062dbbc62 100644 (file)
@@ -86,6 +86,7 @@ _installed_or_uninstalled_test_scripts = \
        tests/test-pull-resume.sh \
        tests/test-pull-basicauth.sh \
        tests/test-pull-repeated.sh \
+       tests/test-pull-sizes.sh \
        tests/test-pull-untrusted.sh \
        tests/test-pull-override-url.sh \
        tests/test-pull-localcache.sh \
index fc429983762b4d859a7138692a90bda9f0915243..4aec588ba3d269f2e6811a007a65e46deee639dd 100644 (file)
@@ -1445,6 +1445,7 @@ _ostree_show() {
     local boolean_options="
         $main_boolean_options
         --print-related
+        --print-sizes
         --raw
     "
 
index a3d9aa4a2083d0379ac91dbc97e6ac76226ffe86..a28f704c50400bcdfe9c174b0945b1910bc0969f 100644 (file)
@@ -99,6 +99,17 @@ Boston, MA 02111-1307, USA.
                 </para></listitem>
             </varlistentry>
 
+            <varlistentry>
+                <term><option>--print-sizes</option></term>
+
+                <listitem><para>
+                    Show the commit size metadata. This in only supported for
+                    commits that contain <varname>ostree.sizes</varname>
+                    metadata. This can be included when creating commits with
+                    <command>ostree commit --generate-sizes</command>.
+                </para></listitem>
+            </varlistentry>
+
             <varlistentry>
                 <term><option>--raw</option></term>
 
index 5091a93c4d47bb7b54a48f28b9ded3c9349c2bb8..96e2d4c6d2ad5aa5affb4ab9773bdb2fa09564bb 100644 (file)
@@ -33,6 +33,7 @@ static gboolean opt_print_related;
 static char* opt_print_variant_type;
 static char* opt_print_metadata_key;
 static char* opt_print_detached_metadata_key;
+static gboolean opt_print_sizes;
 static gboolean opt_raw;
 static gboolean opt_no_byteswap;
 static char *opt_gpg_homedir;
@@ -48,6 +49,7 @@ static GOptionEntry options[] = {
   { "print-variant-type", 0, 0, G_OPTION_ARG_STRING, &opt_print_variant_type, "Memory map OBJECT (in this case a filename) to the GVariant type string", "TYPE" },
   { "print-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_metadata_key, "Print string value of metadata key", "KEY" },
   { "print-detached-metadata-key", 0, 0, G_OPTION_ARG_STRING, &opt_print_detached_metadata_key, "Print string value of detached metadata key", "KEY" },
+  { "print-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_print_sizes, "Show the commit size metadata", NULL },
   { "raw", 0, 0, G_OPTION_ARG_NONE, &opt_raw, "Show raw variant data" },
   { "no-byteswap", 'B', 0, G_OPTION_ARG_NONE, &opt_no_byteswap, "Do not automatically convert variant data from big endian" },
   { "gpg-homedir", 0, 0, G_OPTION_ARG_FILENAME, &opt_gpg_homedir, "GPG Homedir to use when looking for keyrings", "HOMEDIR"},
@@ -146,6 +148,65 @@ do_print_metadata_key (OstreeRepo     *repo,
   return TRUE;
 }
 
+static gboolean
+do_print_sizes (OstreeRepo  *repo,
+                const char  *rev,
+                GError     **error)
+{
+  g_autoptr(GVariant) commit = NULL;
+  if (!ostree_repo_load_variant (repo, OSTREE_OBJECT_TYPE_COMMIT, rev,
+                                 &commit, error))
+    {
+      g_prefix_error (error, "Failed to read commit: ");
+      return FALSE;
+    }
+
+  g_autoptr(GPtrArray) sizes = NULL;
+  if (!ostree_commit_get_object_sizes (commit, &sizes, error))
+    return FALSE;
+
+  gint64 new_archived = 0;
+  gint64 new_unpacked = 0;
+  gsize new_objects = 0;
+  gint64 archived = 0;
+  gint64 unpacked = 0;
+  gsize objects = 0;
+  for (guint i = 0; i < sizes->len; i++)
+    {
+      OstreeCommitSizesEntry *entry = sizes->pdata[i];
+
+      archived += entry->archived;
+      unpacked += entry->unpacked;
+      objects++;
+
+      gboolean exists;
+      if (!ostree_repo_has_object (repo, entry->objtype, entry->checksum,
+                                   &exists, NULL, error))
+        return FALSE;
+
+      if (!exists)
+        {
+          /* Object not in local repo */
+          new_archived += entry->archived;
+          new_unpacked += entry->unpacked;
+          new_objects++;
+        }
+    }
+
+  g_autofree char *new_archived_str = g_format_size (new_archived);
+  g_autofree char *archived_str = g_format_size (archived);
+  g_autofree char *new_unpacked_str = g_format_size (new_unpacked);
+  g_autofree char *unpacked_str = g_format_size (unpacked);
+  g_print ("Compressed size (needed/total): %s/%s\n"
+           "Unpacked size (needed/total): %s/%s\n"
+           "Number of objects (needed/total): %" G_GSIZE_FORMAT "/%" G_GSIZE_FORMAT "\n",
+           new_archived_str, archived_str,
+           new_unpacked_str, unpacked_str,
+           new_objects, objects);
+
+  return TRUE;
+}
+
 static gboolean
 print_object (OstreeRepo          *repo,
               OstreeObjectType     objtype,
@@ -279,6 +340,14 @@ ostree_builtin_show (int argc, char **argv, OstreeCommandInvocation *invocation,
       if (!do_print_variant_generic (G_VARIANT_TYPE (opt_print_variant_type), rev, error))
         return FALSE;
     }
+  else if (opt_print_sizes)
+    {
+      if (!ostree_repo_resolve_rev (repo, rev, FALSE, &resolved_rev, error))
+        return FALSE;
+
+      if (!do_print_sizes (repo, resolved_rev, error))
+        return FALSE;
+    }
   else
     {
       gboolean found = FALSE;
diff --git a/tests/test-pull-sizes.sh b/tests/test-pull-sizes.sh
new file mode 100755 (executable)
index 0000000..8ee07cc
--- /dev/null
@@ -0,0 +1,58 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 Endless Mobile, Inc.
+#
+# SPDX-License-Identifier: LGPL-2.0+
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+set -euo pipefail
+
+. $(dirname $0)/libtest.sh
+
+setup_fake_remote_repo1 "archive" "--generate-sizes"
+
+echo '1..3'
+
+cd ${test_tmpdir}
+mkdir repo
+ostree_repo_init repo
+${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat httpd-address)/ostree/gnomerepo
+
+# Pull commit metadata only. All size and objects will be needed.
+${CMD_PREFIX} ostree --repo=repo pull --commit-metadata-only origin main
+${CMD_PREFIX} ostree --repo=repo show --print-sizes origin:main > show.txt
+assert_file_has_content show.txt 'Compressed size (needed/total): 637[  ]bytes/637[  ]bytes'
+assert_file_has_content show.txt 'Unpacked size (needed/total): 457[  ]bytes/457[  ]bytes'
+assert_file_has_content show.txt 'Number of objects (needed/total): 10/10'
+echo "ok sizes commit metadata only"
+
+# Pull the parent commit so we get most of the objects
+parent=$(${CMD_PREFIX} ostree --repo=repo rev-parse origin:main^)
+${CMD_PREFIX} ostree --repo=repo pull origin ${parent}
+${CMD_PREFIX} ostree --repo=repo show --print-sizes origin:main > show.txt
+assert_file_has_content show.txt 'Compressed size (needed/total): 501[  ]bytes/637[  ]bytes'
+assert_file_has_content show.txt 'Unpacked size (needed/total): 429[  ]bytes/457[  ]bytes'
+assert_file_has_content show.txt 'Number of objects (needed/total): 6/10'
+echo "ok sizes commit partial"
+
+# Finish pulling the commit and check that no objects needed
+${CMD_PREFIX} ostree --repo=repo pull origin main
+${CMD_PREFIX} ostree --repo=repo show --print-sizes origin:main > show.txt
+assert_file_has_content show.txt 'Compressed size (needed/total): 0[  ]bytes/637[  ]bytes'
+assert_file_has_content show.txt 'Unpacked size (needed/total): 0[  ]bytes/457[  ]bytes'
+assert_file_has_content show.txt 'Number of objects (needed/total): 0/10'
+echo "ok sizes commit full"